// run: $exec < input
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

const int maxn=110;
int f[maxn];

struct Edge
{
	int from, to;
	int w;
} edge[maxn * maxn];

int tot;
Edge ans[maxn * maxn];
int cnt;

void add_edge(int u, int v, int w)
{
	edge[tot].from = u; edge[tot].to = v; edge[tot].w = w; tot++;
}

bool cmp1(Edge a, Edge b)
{
	if (a.w != b.w) return a.w < b.w;
	else if (a.from != b.from) return a.from < b.from;
	else return a.to < b.to;
}

bool cmp2(Edge a, Edge b)
{
	if (a.from != b.from) return a.from < b.from;
	else return a.to < b.to;
}
int find(int x)
{
	if (f[x] == -1) return x;
	return f[x] = find(f[x]);
}
void kruscal()
{
	memset(f, -1, sizeof(f));
	cnt = 0;
	for (int k = 0; k < tot; k++) {
		int u = edge[k].from;
		int v = edge[k].to;
		int t1 = find(u);
		int t2 = find(v);
		if (t1 != t2) {
			ans[cnt++] = edge[k];
			f[t1] = t2;
		}
	}
}

int main()
{
	int T; scanf("%d", &T);
	int n;
	while(T--) {
		scanf("%d", &n);
		tot = 0;
		int w;
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++) {
				scanf("%d", &w);
				if (j <= i) continue;
				if (w == 0) continue;
				add_edge(i, j, w);
			}
		std::sort(edge, edge + tot, cmp1);
		kruscal();
		if (cnt != n - 1) { printf("-1\n"); continue; }
		else {
			std::sort(ans, ans + cnt, cmp2);
			for(int i = 0; i < cnt - 1; i++)
				printf("%d %d ", ans[i].from, ans[i].to);
			printf("%d %d\n", ans[cnt-1].from, ans[cnt-1].to);
		}
	}
}

